/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { BaseCommand, CommandDialog, RENDERORDER } from '@amcax/base';
import { CommandFormWrapper } from '@app-base/common/components/command-form';
import { PickInputForFocus } from '@app-base/common/components/command-form/auto-focus/pick-input';
import { CommandFormFooter } from '@app-base/common/components/command-form/footer';
import {
  pickedProductData,
  PickInputValueType,
} from '@app-base/common/components/pick-input/types';
import { DocumentContext } from '@app-base/common/providers/documentProvider';
import { getIdOfPickedObj } from '@app-base/common/utils/render';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { previewer } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { FeaturedCmdDialogParams } from '@app-cad/types';
import { Button } from 'antd';
import i18n from 'i18next';
import { useContext, useEffect, useMemo, useState } from 'react';
import { ColorResult, SketchPicker } from 'react-color';
import { Matrix4, Mesh } from 'three-legacy';
import backButton from './back.svg';
import colorNone from './color-none.svg';
import './style.scss';

enum PickMode {
  FACE = 'face',
  SHELL = 'shell',
  MODEL = 'model',
}

function ChangeColor({ title, onClose }: FeaturedCmdDialogParams) {
  const [mode, setMode] = useState<PickMode>(PickMode.FACE);
  const [includeObjects, setIncludeObjects] = useState<pickedProductData[]>([]);
  const [color, setColor] = useState<string>(null);
  const [pickColor, setPickColor] = useState<string>(null);
  const [displayColorPicker, setdDisplayColorPicker] = useState(false);

  const { documentInfo } = useContext(DocumentContext);
  const isPart = documentInfo.type === 'part';

  useEffect(() => {
    previewer.clear();

    if (!isFormDataValid()) {
      return;
    }

    if (color) {
      preview(color);
    }
  }, [mode, includeObjects, color]);

  const isFormDataValid = () => {
    return includeObjects.length > 0;
  };

  useEffect(() => {
    setIncludeObjects([]);
  }, [mode]);

  const openColorCard = () => {
    setdDisplayColorPicker(true);
    if (pickColor) {
      preview(pickColor);
    }
  };

  const closeColorCard = () => {
    setdDisplayColorPicker(false);
    if (color) {
      preview(color);
    } else {
      previewer.clear();
    }
  };

  const handleColorChange = (newColor: ColorResult) => {
    setPickColor(newColor.hex);
    preview(newColor.hex);
  };

  const preview = (previewColor: string) => {
    function appendPreviewObject(
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      obj: any,
      matrices: Matrix4[],
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      objs: any[],
    ) {
      matrices.forEach((matrix) => obj.applyMatrix4(matrix));
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const { mesh } = obj as any;
      if (mesh as Mesh) {
        if (mesh.material) {
          mesh.material.color?.set?.(previewColor);
          mesh.material.opacity = 1.0;
        }

        mesh.renderOrder = RENDERORDER.MESH_H + 1;
      }
      objs.push(obj);
    }

    const models = includeObjects.reduce((objs, includeObject) => {
      const matrix = includeObject.assisObj.matrix;
      if (mode === PickMode.FACE || mode === PickMode.MODEL) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const obj = includeObject.assisObj.cloneSelf() as any;
        appendPreviewObject(obj, [matrix], objs);
      } else if (mode === PickMode.SHELL) {
        includeObject.assisObj.childObjects?.forEach((assObj) => {
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          const obj = assObj.cloneSelf() as any;
          appendPreviewObject(obj, [assObj.matrix, matrix], objs);
        });
      }
      return objs;
    }, []);
    previewer.preview(models);
  };

  const finishValid = useMemo(isFormDataValid, [mode, includeObjects, color]);

  const execute = async () => {
    const asmDxids = [],
      asmProperties = [];
    if (mode === PickMode.FACE || mode === PickMode.MODEL) {
      asmDxids.push(
        ...includeObjects.reduce((dxids, info) => {
          dxids.push(getIdOfPickedObj(info));
          asmProperties.push({ color: color });
          return dxids;
        }, []),
      );
    } else if (mode === PickMode.SHELL) {
      asmDxids.push(
        ...includeObjects.reduce((dxids, info) => {
          dxids.push(info.idInfo.o + ':all');
          return dxids;
        }, []),
      );
      asmProperties.push(
        ...includeObjects.reduce(
          (properties, info) => {
            const originProperty = info.assemblyInfo?.color?.all;
            const property: { opacity?: number; color?: string } = {};
            if (originProperty?.a !== undefined) {
              property.opacity = originProperty.a;
            }
            property.color = color;
            properties.push(property);
            return properties;
          },
          [] as { opacity?: number; color?: string }[],
        ),
      );
    }
    await wsApi.setColorAndOpacity(asmDxids, asmProperties);
    exit();
  };

  const checkAndFinish = async () => {
    if (!isFormDataValid()) {
      return;
    }
    execute();
    exit();
  };

  const exit = () => {
    previewer.clear();
    onClose();
  };

  // =================
  useCommand('change-color', {
    onClose,
    finishDraw: checkAndFinish,
  });

  return (
    <CommandDialog
      title={title}
      onClose={onClose}
      placement='topLeft'
      className='cmd-change-color'
    >
      {!displayColorPicker ? (
        <CommandFormWrapper>
          <div className='flexDiv'>
            <label>选择类型</label>
            <select
              className='selectClass'
              defaultValue={mode}
              onChange={(e) => {
                setMode(e.target.value as PickMode);
              }}
            >
              <option value={PickMode.FACE}>面</option>
              {isPart && <option value={PickMode.MODEL}>体</option>}
              {!isPart && <option value={PickMode.SHELL}>集</option>}
            </select>
          </div>
          {mode === PickMode.FACE && (
            <PickInputForFocus
              allowPickType={[PickInputValueType.Surface]}
              onPick={(v) => {
                setIncludeObjects(v);
              }}
              autoFocus
              placeholder='请选择一个面'
              value={includeObjects}
              isMulti
              allowPickInvisibleAssembleFromLeftPanel
            />
          )}
          {mode === PickMode.MODEL && (
            <PickInputForFocus
              allowPickType={[PickInputValueType.Model]}
              onPick={(v) => {
                setIncludeObjects(v);
              }}
              autoFocus
              placeholder='请选择模型'
              value={includeObjects}
              isMulti
              allowPickInvisibleAssembleFromLeftPanel
            />
          )}
          {mode === PickMode.SHELL && (
            <PickInputForFocus
              allowPickType={[PickInputValueType.Product]}
              onPick={(v) => {
                setIncludeObjects(v);
              }}
              autoFocus
              placeholder='请选择零件/子装配'
              value={includeObjects}
              isMulti
              // highlightSelection={interferenceResult.length === 0}
              allowPickInvisibleAssembleFromLeftPanel
            />
          )}
          <div className='flexDiv'>
            <label>设置颜色</label>
            {color ? (
              <div
                className='colorBotton'
                onClick={() => {
                  openColorCard();
                }}
                style={{
                  backgroundColor: color,
                }}
              />
            ) : (
              <Button
                className='colorBotton'
                icon={<img src={colorNone} />}
                onClick={() => {
                  openColorCard();
                }}
              />
            )}
          </div>
          <CommandFormFooter
            isSubmitDisabled={!finishValid}
            onSubmit={execute}
            onClose={onClose}
            submitText='完成'
            // isSubmitLoading={isLoading}
          />
        </CommandFormWrapper>
      ) : null}
      {displayColorPicker ? (
        <CommandFormWrapper>
          <Button
            className='backButton'
            icon={<img src={backButton} />}
            onClick={() => {
              closeColorCard();
            }}
          >
            <label>颜色选择器</label>
          </Button>
          <SketchPicker
            color={pickColor || '#ff6347'}
            onChange={handleColorChange}
            disableAlpha={true}
            width='auto'
            className='custom-sketch-picker'
            presetColors={[
              '#ffffff',
              '#c0c0c0',
              '#808080',
              '#000000',
              '#ff0000',
              '#800000',
              '#804040',
              '#d3b27d',
              '#ffff00',
              '#808000',
              '#00ff00',
              '#008000',
              '#008080',
              '#0080ff',
              '#00ffff',
              '#0000ff',
              '#000080',
              '#7f00ff',
              '#ff00ff',
              '#fe8081',
            ]}
          />
          <CommandFormFooter
            isSubmitDisabled={!pickColor}
            onSubmit={() => {
              if (pickColor) {
                setColor(pickColor);
              }
              closeColorCard();
            }}
            onClose={onClose}
            showCancel={false}
            submitText='应用'
          />
        </CommandFormWrapper>
      ) : null}
    </CommandDialog>
  );
}

export const cmdChangeColor: BaseCommand = {
  id: 'CmdChangeColor',
  label: 'command.change-color',
  icon: 'commands/product/color',
  create: (label, onClose, props) => (
    <ChangeColor
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
